Issue#3828 Refatorar Mesa Diretora#3829
Conversation
There was a problem hiding this comment.
A motivação conceitual do PR é correta (Mesa Diretora pertence à Legislatura, não à
SessaoLegislativa). Isso é uma das muitas "heranças malditas" da modelagem de dados (mal feita!) do SAPL 2.5 e anteriores. A simplificação do AJAX/jQuery para CRUDs padrão é bem vinda. Os problemas abaixo precisam ser resolvidos antes do merge.
|
|
||
| url(r'^mesa-diretora/remove-parlamentar-composicao/$', | ||
| remove_parlamentar_composicao, name='remove_parlamentar_composicao'), | ||
| url(r'^mesa-diretora/', include( |
There was a problem hiding this comment.
URL renomeada quebra redireciona_urls
A URL sapl.parlamentares:mesa_diretora foi renomeada para mesadiretora_list, mas duas referências fora do diff continuam apontando para o nome antigo:
sapl/redireciona_urls/views.py:34—parlamentar_mesa_diretora = (app_parlamentares + ':mesa_diretora'). Vai dispararUnknownUrlNameErrorquando alguém acessar/consultas/mesa_diretora/mesa_diretora_index_html(uso emviews.py:495).sapl/redireciona_urls/tests.py:140—reverse('sapl.parlamentares:mesa_diretora')quebra a suíte.
Atualizar ambos para mesadiretora_list.
| migrations.AlterField( | ||
| model_name='mesadiretora', | ||
| name='data_inicio', | ||
| field=models.DateField(verbose_name='Data Início'), |
There was a problem hiding this comment.
Migration pode falhar em bases legadas
O modelo antigo permitia data_inicio/data_fim nulos em MesaDiretora (null=True). Fluxo atual:
0046popula essas datas a partir desessao_legislativa, mas só replica os valores que a sessão tinha.0048populatituloapenas ondedata_inicio IS NOT NULL AND data_fim IS NOT NULL.0049(esta migration) aplicaNOT NULLem ambas.
Se houver MesaDiretora cuja sessão não tinha datas (ou o join falhar), 0049 quebra com IntegrityError no upgrade. Como as bases dos clientes são bem heterogêneas, sugiro:
- Em
0046(ou nova migration intermediária), preencher fallback antes doAlterFieldparaNOT NULL— por exemplo, copiar das datas da legislatura quando a sessão não tiver. - Rodar a migration contra alguns dumps reais antes do release.
| def __init__(self, *args, **kwargs): | ||
| super(ComposicaoMesaForm, self).__init__(*args, **kwargs) | ||
| self.instance.mesa_diretora = self.initial.get('mesa_diretora') | ||
| self.fields['parlamentar'].queryset = self.fields['parlamentar'].queryset.filter( |
There was a problem hiding this comment.
ComposicaoMesaForm.__init__ quebra silenciosamente sem initial
Se o form for instanciado sem initial['mesa_diretora'], self.initial.get(...) retorna None e a próxima linha lança AttributeError: 'NoneType' object has no attribute 'legislatura'.
Hoje as views CRUD sempre passam initial, então não dispara em produção, mas qualquer caller futuro (admin, comando, outra view) quebra silenciosamente. Sugestão de guarda:
mesa = self.initial.get('mesa_diretora')
if mesa is not None:
self.instance.mesa_diretora = mesa
self.fields['parlamentar'].queryset = (
self.fields['parlamentar'].queryset
.filter(mandato__legislatura=mesa.legislatura)
)| ultima_filiacao = self.filiacao_set.order_by('-data').first() | ||
| # este método conta com a ordenação default do model Filiacao para trazer a última filiação primeiro | ||
| # se order_by for adicionado aqui, o prefetch_related que inclui filiacao_set não irá pré-carregar como esperado | ||
| ultima_filiacao = self.filiacao_set.first() |
There was a problem hiding this comment.
filiacao_atual agora depende da ordenação default — vale um teste regressivo
A troca por self.filiacao_set.first() é correta porque Filiacao.Meta.ordering = ('parlamentar', '-data', '-data_desfiliacao'), e o prefetch_related adicionado na ListView depende disso para não disparar query extra. O comentário deixa o motivo claro — ótimo.
Sugestão: adicionar um teste curto que verifique o invariante (criar duas filiações em datas diferentes e checar parlamentar.filiacao_atual). Se um dia alguém mexer no Meta.ordering, o teste pega.
|
|
||
| def clean(self): | ||
| if self.data_inicio and self.data_fim: | ||
| if self.data_inicio >= self.data_fim: |
There was a problem hiding this comment.
Validação >= rejeita mesas de um único dia
Há cenários reais de mesa que dura um único dia (dissolução e recriação no mesmo dia, por cassação ou eventos extraordinários — exatamente o tipo de exceção citado na descrição do PR).
Considerar > em vez de >=, esse requisito precisa ser refinado... o que acha @edwardoliveira
|
|
||
| def get_filterset_kwargs(self, filterset_class): | ||
| fk = super().get_filterset_kwargs(filterset_class) | ||
| if 'legislatura' not in self.request.GET and not 'mesa' in self.request.GET: |
There was a problem hiding this comment.
NIT: not 'mesa' in self.request.GET → 'mesa' not in self.request.GET (PEP 8). Mesma observação na linha de baixo.
| return _('Mesa da %(sessao)s sessao da %(legislatura)s Legislatura') % { | ||
| 'sessao': self.sessao_legislativa, 'legislatura': self.sessao_legislativa.legislatura | ||
| } | ||
| return self.titulo or _('%(legislatura)s - %(data_inicio)s a %(data_fim)s') % { |
There was a problem hiding this comment.
Datas em __str__ saem em ISO (2021-01-01) em vez do formato pt-br. Como titulo agora é o caminho principal, é raro cair no fallback, mas vale usar django.utils.formats.date_format(d, "SHORT_DATE_FORMAT") para consistência com o resto da aplicação.
| {% endblock actions_search %} | ||
|
|
||
| {% block container_table_list %} | ||
| {% if perms.parlamentares.add_mesadiretora %} |
There was a problem hiding this comment.
o template usa add_mesadiretora para alternar entre listagem CRUD (admin) e visualização em abas (público). Funcionalmente está consistente com o resto do SAPL. Só ponderando se change_mesadiretora não seria semanticamente mais correto para representar "tem painel de gestão".
| {{composicao.parlamentar.nome_parlamentar}}</a> | ||
| </div> | ||
| </td> | ||
| <td>{{composicao.parlamentar.filiacao_atual}}</td> |
There was a problem hiding this comment.
Partido pode divergir do partido da época
A view antiga (partido_parlamentar_sessao_legislativa) calculava a filiação na data da sessão. Esta agora mostra sempre a filiação mais recente. Para mesas atuais é a mesma coisa; para mesas históricas pode mostrar partido errado (ex.: parlamentar que mudou de partido depois).
É bom validar esse requisito também, @edwardoliveira . Se não for o caso, vale reintroduzir a lógica por data (ex.: método filiacao_em(data) no model).
| 'cargo': new_cargo.id, | ||
| }) | ||
|
|
||
| composicao.refresh_from_db() |
There was a problem hiding this comment.
a cobertura dos forms está boa. mas acho que tem alguns pontos faltantes:
MesaDiretoraFilterSet: testar que?mesa=<id>resolve para a legislatura correta e que sem GET cai na legislatura atual; testar 404 para mesa inexistente.- View pública (
mesadiretora_filter.html): renderizar a página sem permissão de admin e validar as abas. test_composicaomesa_form_view_create/update: não fazem assert de status HTTP — adicionar pelo menosassert response.status_code in (200, 302)para detectar erros de form silenciosos.- Variáveis
mandato/mandato1/mandato2criadas mas nunca lidas — substituir por_ = baker.make(...)para deixar a intenção clara.
NIT: faltou newline final no arquivo. (conferir isso nos demais arquivos)
Refatora Mesa Diretora para utilizar o Crud de forma simplifica da criação e edição de mesas e composições
Descrição
npm run buildIssue Relacionada
#3828
Nesta issue estão os requisitos funcionais e não funcionais, além da citação de várias outras issues que envolvem o tema
Motivação e Contexto
Mesas Diretoras nunca tiveram ligação conceitual com sessão legislativa. Sessão Legislativa possui uma definição e existência específica: inicia-se em meados de fevereiro e termina-se em meados de dezembro e diz sobre o intervalo onde haverá sessões plenárias.
Mesa diretora não: Mesa diretora, salvo raríssimas exceções, iniciam-se em 1º de janeiro e conclui-se com um ou dois anos. Dentro das exceções, estão a finalização inesperada de uma mesa e inicio de outra, seja por cassação de algum parlamentar, ou outro motivo qualquer que interrompa uma mesa e inicia-se outra.
Regras de não interseção entre mesas; de contenção em legislatura; de cargo único (que já existia); de só parlamentares da legislatura; de não duplicidade de parlamentar foram colocadas nos forms.
Como Isso Foi Testado?
foi criado o sapl/parlamentares/tests/test_mesadiretora.py que testa os forms
Capturas de Tela (se apropriado):
Tela Pública com 3 Mesas na mesma Legislatura. Nota-se os TABs com as três mesas, onde o Biênio de 23/24 possui duas mesas com datas de inicio e encerramento.

Tela de listagem do CRUDs tradicional para usuário que possui permissão de edição de mesa:


Tela de listagem das composições de uma mesa

Tipos de Mudanças
Checklist: